// Copyright(c) 2008 Tri Tech Information Systems Inc. 
// Distributed under the Boost Software License, Version 1.0.
//     (See accompanying file ../../LICENSE_1_0.txt or copy at
//           http://www.boost.org/LICENSE_1_0.txt)
//     
#ifndef INCLUDE_PYTHON_INTERFACE_H
#define INCLUDE_PYTHON_INTERFACE_H

#include <boost/python.hpp>
#include <pyxx/python_error.h>
#include <boost/type_traits/is_void.hpp>
#include <boost/type_traits/is_polymorphic.hpp>
#include <boost/mpl/if.hpp>
#include <iostream>

// This method returns a logic_error which is presumably then thrown        
// It produces an informative message about which virtual function is missing
inline std::logic_error pure_virtual_call_error(boost::python::object self, const char * name) 
{
    using namespace boost::python;
    object myclass = self.attr("__class__");

    std::string full_name = extract<std::string>(
        myclass.attr("__module__") + str(".") + myclass.attr("__name__"));

    return std::logic_error(name + (" called on " + full_name) + " which has no overrider"); 
}           

template<typename From, typename To, bool IsPoly>
struct my_dynamic_cast
{
};

template<typename From, typename To>
struct my_dynamic_cast<From, To, true>
{
    static   To * execute(From * f)
    {
        return dynamic_cast<To*>(f);
    }
};

template<typename From, typename To>
struct my_dynamic_cast<From, To, false>
{
    static   To * execute(From * f)
    {
        return 0;
    }
};


template<typename HoldType, typename WrapperType>
struct expose_wrapper
{
    typedef expose_wrapper<HoldType, WrapperType> this_type;
    
    static void* convert_lvalue( PyObject* obj )
    {
        using namespace boost::python;

        extract<HoldType&> extractor( object( handle<>(borrowed(obj)) ) );
        if(!extractor.check())
            return 0;

        HoldType & held = extractor();

        return my_dynamic_cast<typename HoldType::element_type, WrapperType, 
               boost::is_polymorphic<typename HoldType::element_type>::value 
                   >::execute( get_pointer(held) );

    }

    expose_wrapper()
    {
        using namespace boost::python;
        converter::registry::insert(
            &this_type::convert_lvalue,
            type_id<WrapperType>() );
    }
};

/*
   IWrapper provides an interface that allows some operations to be performed on any wrapper
*/
struct IWrapper
{
    typedef void (*release_func)(IWrapper*);
    virtual void take_ownership(release_func release) = 0;
    virtual boost::python::object self() const = 0;
    virtual bool owned() = 0;
};

#endif
